<template>
  <div class="cm-table">
    <table>
      <thead>
        <tr>
          <!-- 表头循环 -->
          <th v-for="col in columns" :key="col.key">
            <div>
              <!-- 先判断 type -->
              <template v-if="col.type === 'selection'">
                <input
                  ref="allCheck"
                  type="checkbox"
                  :checked="isSelectAll"
                  @change="selectAll"
                />
              </template>
              <template v-else>
                <span>{{ col.title }}</span>
                <span v-if="col.sortable">
                  <i @click="handleSort(col.key, 'asc')">↑ </i>
                  <i @click="handleSort(col.key, 'desc')"> ↓</i>
                </span>
                <span v-if="col.filterable">
                  <select v-model="filterData">
                    <option value="">全部</option>
                    <option
                      v-for="filterItem in filterJob"
                      :key="filterItem.index"
                    >
                      {{ filterItem }}
                    </option>
                  </select>
                </span>
              </template>
            </div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="row in dataSource.dataList" :key="row.id">
          <td v-for="col in columns" :key="col.key">
            <div>
              <template v-if="col.type === 'selection'">
                <input
                  type="checkbox"
                  :checked="formateStatus(row)"
                  @change="toggleSelect($event, row)"
                />
              </template>
              <template v-else>
                {{ row[col.key] }}
              </template>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
    <p class="pagination">
      <a @click="changePage(-1)">上一页</a>
      当前第<input disabled v-model="page" type="text" class="page" />页 共{{
        dataSource.pageCurrent
      }}页
      <a @click="changePage(1)">下一页</a>
    </p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selectRows: [], // 当前已选中的行
      page: 1, // 当前页
      filterData: "", // 过滤选择的数据
      filterJob: [], // 下拉框选项
      dataList: this.dataSource.dataList.slice(), // 数据初始化
    };
  },
  props: {
    columns: {
      type: Array,
      default: () => [],
    },
    dataSource: {
      type: Object,
      default: () => {},
    },
  },
  watch: {
    // 监听下拉框所选数据
    filterData(newVal) {
      if (newVal === "") {
        let pageSize = this.dataSource.pageSize;
        let start = (this.page - 1) * pageSize;
        let end = this.page * pageSize;
        this.dataSource.dataList = this.dataList.slice(start, end);
      } else {
        this.dataSource.dataList = this.dataList.filter(
          (item) => item.job === newVal
        );
      }
    },
  },
  computed: {
    isSelectAll() {
      // 是否全选
      let all = this.dataSource.dataList.map((item) => item.id).sort();
      let selected = this.selectRows.map((item) => item.id).sort();
      let isSelect = true;
      if (all.length === selected.length) {
        for (let i = 0, len = all.length; i < len; i++) {
          if (all[i] !== selected[i]) {
            isSelect = false;
            break;
          }
        }
      } else {
        isSelect = false;
      }
      this.$nextTick(() => {
        //这个是选了部分之后把表头的复选框改变成中间状态（就是横杠的状态）
        this.$refs["allCheck"][0].indeterminate = selected.length && !isSelect;
      });
      return isSelect;
    },
  },
  created() {
    this.dataSource.dataList = this.dataList.slice(0, this.dataSource.pageSize);
    let arr = this.dataSource.dataList.map((item) => item.job);
    this.filterJob = Array.from(new Set(arr));
  },
  methods: {
    selectAll(e) {
      // 单击表头的多选框并触发事件
      let checked = e.target.checked;
      this.selectRows = checked
        ? JSON.parse(JSON.stringify(this.dataSource.dataList))
        : [];
      this.$emit("on-select-change", this.selectRows);
    },
    // 单点每一行的checkbox
    toggleSelect(e, row) {
      let checked = e.target.checked;
      if (checked) {
        this.selectRows.push(row);
      } else {
        let idx = this.selectRows.findIndex((item) => item.id === row.id);
        this.selectRows.splice(idx, 1);
      }
      this.$emit(
        "on-select-change",
        JSON.parse(JSON.stringify(this.selectRows))
      );
    },
    formateStatus(row) {
      // 表体的每个多选框是否被勾选
      return this.selectRows.findIndex((item) => item.id === row.id) >= 0;
    },
    handleSort(key, sortType) {
      // 由于一般排序更偏向后端处理，前端排序无太大意义，所以这里只是简单的处理一下
      if (sortType === "asc") {
        this.dataSource.dataList.sort((a, b) => a.age - b.age);
      } else {
        this.dataSource.dataList.sort((a, b) => b.age - a.age);
      }
      this.$emit("on-sort", { key, sortType });
    },
    // 分页
    changePage(num) {
      let pageSize = this.dataSource.pageSize;
      if (num === 1) {
        if (this.page < this.dataSource.pageCurrent) {
          this.page++;
          let start = (this.page - 1) * pageSize + 1;
          let end = this.page * pageSize;
          this.dataSource.dataList = this.dataList.slice(start - 1, end);
          let arr = this.dataSource.dataList.map((item) => item.job);
          this.filterJob = Array.from(new Set(arr));
        } else {
          window.alert("已是最后一页");
        }
      } else {
        if (this.page > 1) {
          this.page--;
          let start = (this.page - 1) * pageSize + 1;
          let end = this.page * pageSize;
          this.dataSource.dataList = this.dataList.slice(start - 1, end);
          let arr = this.dataSource.dataList.map((item) => item.job);
          this.filterJob = Array.from(new Set(arr));
        } else {
          window.alert("已是第一页");
        }
      }
    },
  },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
a {
  text-decoration: none;
  color: #5c6b77;
}
table td,
table th {
  padding: 8px 16px;
  border: 1px solid #e9e9e9;
  text-align: left;
}
.cm-table table {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
  empty-cells: show;
  border: 1px solid #e9e9e9;
}
.cm-table table th {
  background: #f7f7f7;
  color: #5c6b77;
  font-weight: 600;
  white-space: nowrap;
}
.pagination {
  text-align: center;
}
.page {
  width: 4em;
  text-align: center;
}
</style>
